package plantshop.tests;

import static org.junit.Assert.*;

import java.util.LinkedList;
import java.util.List;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import plantshop.model.Characteristics;
import plantshop.model.CollisionDetector;
import plantshop.model.Creature;
import plantshop.model.Customer;
import plantshop.model.Location;
import plantshop.model.Store;
import plantshop.model.plants.*;

public class StoreTest {
	Store test1, test2;

	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
	}

	@AfterClass
	public static void tearDownAfterClass() throws Exception {
	}

	@Before
	public void setUp() throws Exception {
		test1 = new Store(300,1,1);
		test2 = new Store(300,1,1);
	}

	@After
	public void tearDown() throws Exception {
		test1 = null;
		test2 = null;
	}

	@Test
	public void testBuyPlant() {
		Plant p = new WhiteOak();
		test1.buyPlant(0, 4,p);
		assertEquals(300-20,test1.getMoney());
		assertEquals(p,test1.getBack().get(0).getPlant(4));
	}

	@Test
	public void testCreateCreature() {
		Creature c = new Creature(2);
		test1.createCreature(c);
		assertEquals(c,test1.getCreatures().get(0));
		assertEquals(1,test1.getCreatures().size());
		
		test1.createCreature(null);
		assertEquals(1,test1.getCreatures().size());
	}

	@Test
	public void testAddPlant() {
		Plant p = new WhiteOak();
		Plant p1 = new Aster();
		assertTrue(test1.addPlant(true, 0, 3, p));
		assertEquals(p,test1.getFront().get(0).getPlant(3));
		assertEquals(575,test1.getAttractiveness());
		assertTrue(test1.addPlant(true, 0, 2, p));
		assertEquals(635,test1.getAttractiveness());
		assertFalse(test1.addPlant(true, 0, 2, p1));
		assertEquals(p,test1.getFront().get(0).getPlant(2));
		
		assertTrue(test2.addPlant(false, 0, 3, p));
		assertEquals(p,test2.getBack().get(0).getPlant(3));
		assertEquals(500,test2.getAttractiveness());
		assertTrue(test2.addPlant(false, 0, 2, p));
		assertEquals(500,test2.getAttractiveness());
		assertFalse(test2.addPlant(false, 0, 1, null));

		Store testOOB = new Store(300,1,1);
		assertFalse(testOOB.addPlant(false, 0, 150, p));
		assertFalse(testOOB.addPlant(false, -15, 0, p));
	}

	@Test
	public void testMarkPlant() {
		Plant p = new Aster();
		test1.addPlant(true, 0, 2, p);
		test1.markPlant(0, 3);
		assertTrue(test1.getFront().get(0).getPlant(2).getAvailable());
		test1.markPlant(0, 2);
		assertFalse(test1.getFront().get(0).getPlant(2).getAvailable());
		test1.markPlant(400, -30);
		test1.markPlant(0, -30);
	}

	@Test
	public void testAddCustomer() {
		Customer c = Customer.makeCustomer();
		test1.addCustomer(c);
		assertEquals(1,test1.getCustomers().size());
		test1.addCustomer(null);
		assertEquals(1,test1.getCustomers().size());
		test1.addCustomer(c);
		assertEquals(2,test1.getCustomers().size());
		assertTrue(test1.getCustomers().contains(c));
	}

	@Test
	public void testRemoveCustomerCustomer() {
		Customer c1 = Customer.makeCustomer(), c2 = Customer.makeCustomer();
		test1.addCustomer(c1);
		test1.addCustomer(c2);
		assertTrue(test1.getCustomers().contains(c1));
		assertTrue(test1.getCustomers().contains(c2));
		test1.removeCustomer(null);
		assertTrue(test1.getCustomers().contains(c1));
		assertTrue(test1.getCustomers().contains(c2));
		test1.removeCustomer(c1);
		assertFalse(test1.getCustomers().contains(c1));
		assertTrue(test1.getCustomers().contains(c2));
		assertEquals(1,test1.getCustomers().size());
		test1.removeCustomer(Customer.makeCustomer());
		assertTrue(test1.getCustomers().contains(c2));
	}

	@Test
	public void testRemoveCustomerInt() {
		Customer c1 = Customer.makeCustomer(), c2 = Customer.makeCustomer();
		test1.addCustomer(c1);
		test1.addCustomer(c2);
		assertTrue(test1.getCustomers().contains(c1));
		assertTrue(test1.getCustomers().contains(c2));
		test1.removeCustomer(5);
		assertTrue(test1.getCustomers().contains(c1));
		assertTrue(test1.getCustomers().contains(c2));
		test1.removeCustomer(-1);
		assertTrue(test1.getCustomers().contains(c1));
		assertTrue(test1.getCustomers().contains(c2));
		test1.removeCustomer(1);
		assertTrue(test1.getCustomers().contains(c1));
		assertFalse(test1.getCustomers().contains(c2));
	}

	@Test
	public void testRemoveCreature() {
		Creature c = new Creature(1);
		test1.createCreature(c);
		assertTrue(test1.getCreatures().contains(c));
		test1.removeCreature(null);
		assertTrue(test1.getCreatures().contains(c));
		test1.removeCreature(c);
		assertFalse(test1.getCreatures().contains(c));
	}

	@Test
	public void testGetCustomers() {
		Customer c1 = Customer.makeCustomer();
		Customer c2 = Customer.makeCustomer();
		test1.addCustomer(c1);
		test1.addCustomer(c2);
		
		List<Customer> c = test1.getCustomers();
		assertTrue(c.contains(c1));
		assertTrue(c.contains(c2));
		
		Customer c3 = Customer.makeCustomer();
		c.add(c3);
		assertFalse(test1.getCustomers().contains(c3));
	}

	@Test
	public void testGetCreatures() {
		Creature c1 = new Creature(1);
		Creature c2 = new Creature(2);
		test1.createCreature(c1);
		test1.createCreature(c2);
		
		List<Creature> c = test1.getCreatures();
		assertTrue(c.contains(c1));
		assertTrue(c.contains(c2));
		
		Creature c3 = new Creature(1);
		c.add(c3);
		assertFalse(test1.getCreatures().contains(c3));
	}

	@Test
	public void testSellPlant() {
		Plant p1 = new JapaneseBarberry();
		Plant p2 = new WhiteOak();
		Plant p3 = new SweetPepperbush();
		test1.addPlant(true, 0, 1, p1);
		test1.addPlant(true, 1, 3, p2);
		test1.addPlant(true, 1, 0, p3);
		assertEquals(300,test1.getMoney());
		assertEquals(0,test1.getSales());
		assertEquals(675,test1.getAttractiveness());
		
		test1.sellPlant(1,7);
		assertEquals(300,test1.getMoney());
		assertEquals(0,test1.getSales());
		assertEquals(675,test1.getAttractiveness());
		
		test1.sellPlant(0, 1);
		assertEquals(320,test1.getMoney());
		assertEquals(1,test1.getSales());
		assertEquals(637,test1.getAttractiveness());
		
		test1.sellPlant(-1, 0);
		
		test1.sellPlant(1, 0);
		assertEquals(355,test1.getMoney());
		assertEquals(2,test1.getSales());
		assertEquals(749,test1.getAttractiveness());
	}

	@Test
	public void testSellRequestedPlant() {
		Customer c = Customer.makeCustomer(1,new Characteristics(new int[]{5,5,10,5,5}));
		test1.addCustomer(c);
		
		Plant p1 = new NorwayMaple();
		Plant p2 = new WhiteOak();
		Plant p3 = new SweetPepperbush();
		Plant p4 = new BurningBush();
		test1.addPlant(true, 0, 1, p1);
		test1.addPlant(true, 1, 3, p2);
		test1.addPlant(true, 1, 0, p3);
		test1.addPlant(false, 0, 3, p4);
		test1.addPlant(true, 0, 2, p4);
		test1.addPlant(false, 0, 0, p2);
		test1.addPlant(false, 0, 1, p3);
		test1.addPlant(false, 0, 5, p1);
		
		test1.sellRequestedPlant(false, 0, 7, c.getDesiredPlant().getDominant(), c);
		assertEquals(300,test1.getMoney());
		assertEquals(0,test1.getSales());
		assertEquals(700,test1.getAttractiveness());
		
		test1.sellRequestedPlant(false, 0, 3, c.getDesiredPlant().getDominant(), c);
		assertEquals(350,test1.getMoney());
		assertEquals(1,test1.getSales());
		assertEquals(675,test1.getAttractiveness());
		
		test1.sellRequestedPlant(true, 1, 3, c.getDesiredPlant().getDominant(), c);
		assertEquals(550,test1.getMoney());
		assertEquals(2,test1.getSales());
		assertEquals(900,test1.getAttractiveness());
		
		test1.sellRequestedPlant(true, 1, 0, c.getDesiredPlant().getDominant(), c);
		assertEquals(655,test1.getMoney());
		assertEquals(3,test1.getSales());
		assertEquals(1125,test1.getAttractiveness());
		
		test1.sellRequestedPlant(true, 0, 1, c.getDesiredPlant().getDominant(), c);
		assertEquals(725,test1.getMoney());
		assertEquals(4,test1.getSales());
		assertEquals(1075,test1.getAttractiveness());
		
		test1.sellRequestedPlant(true, 0, 2, c.getDesiredPlant().getDominant(), c);
		assertEquals(775,test1.getMoney());
		assertEquals(5,test1.getSales());
		assertEquals(1025,test1.getAttractiveness());
		
		test1.sellRequestedPlant(false, 0, 0, c.getDesiredPlant().getDominant(), c);
		assertEquals(975,test1.getMoney());
		assertEquals(6,test1.getSales());
		assertEquals(1212,test1.getAttractiveness());
		
		test1.sellRequestedPlant(false, 0, 1, c.getDesiredPlant().getDominant(), c);
		assertEquals(1080,test1.getMoney());
		assertEquals(7,test1.getSales());
		assertEquals(1399,test1.getAttractiveness());
		
		test1.sellRequestedPlant(false, 0, 5, c.getDesiredPlant().getDominant(), c);
		assertEquals(1150,test1.getMoney());
		assertEquals(8,test1.getSales());
		assertEquals(1374,test1.getAttractiveness());
		//Bad cases
		test1.sellRequestedPlant(false,-1,0,0,c);
		test1.sellRequestedPlant(false, 0, -1, 0, c);
		test1.sellRequestedPlant(true, 0, 5, 0, c);
		
		test1.sellRequestedPlant(false, 0, 15, 0, c);
		test1.sellRequestedPlant(false, 1, 0, 0, c);
	}

	@Test
	public void testGetPlant() {
		Plant p1 = new JapaneseBarberry();
		Plant p2 = new WhiteOak();
		Plant p3 = new SweetPepperbush();
		Plant p4 = new BurningBush();
		test1.addPlant(true, 0, 1, p1);
		test1.addPlant(true, 1, 3, p2);
		test1.addPlant(true, 1, 0, p3);
		test1.addPlant(false, 0, 3, p4);
		
		assertEquals(p1,test1.getPlant(true, 0, 1));
		assertEquals(p2,test1.getPlant(true, 1, 3));
		assertEquals(p3,test1.getPlant(true, 1, 0));
		assertEquals(p4,test1.getPlant(false, 0, 3));
		assertEquals(null,test1.getPlant(true, 4, 0));
		assertEquals(null,test1.getPlant(false, 0, 1));
		assertEquals(null,test1.getPlant(true, -1, 0));
		assertEquals(null,test1.getPlant(true, 0, -1));
		assertEquals(null,test1.getPlant(true,0,160));
		assertEquals(null,test1.getPlant(true, 2, 0));
		assertEquals(null,test1.getPlant(false, 1, 0));	
	}

	@Test
	public void testRemovePlant() {
		Plant p1 = new JapaneseBarberry();
		Plant p2 = new WhiteOak();
		Plant p3 = new SweetPepperbush();
		Plant p4 = new BurningBush();
		test1.addPlant(true, 0, 1, p1);
		test1.addPlant(true, 1, 3, p2);
		test1.addPlant(true, 1, 0, p3);
		test1.addPlant(false, 0, 3, p4);
		test1.addPlant(true, 0, 2, p2);
		assertEquals(2,test1.getCounts().get(p2).intValue());
		
		
		test1.removePlant(false, 0, 5);
		assertEquals(735,test1.getAttractiveness());
		assertEquals(1,test1.getBack().get(0).getPlantCounts().get(p4).intValue());
		
		test1.removePlant(true, 0, 1);
		assertEquals(710,test1.getAttractiveness());
		assertFalse(test1.getFront().get(0).getPlantCounts().keySet().contains(p1));
		
		test1.removePlant(true, 0, 2);
		assertEquals(650,test1.getAttractiveness());
		assertEquals(1,test1.getCounts().get(p2).intValue());
	}

	@Test
	public void testUpdateAttractiveness() {
		Plant p1 = new JapaneseBarberry();
		Plant p2 = new WhiteOak();
		Plant p3 = new SweetPepperbush();
		Plant p4 = new BurningBush();
		
		assertEquals(500,test1.getAttractiveness());
		test1.addPlant(true, 0, 1, p1);
		assertEquals(525,test1.getAttractiveness());
		test1.addPlant(true, 1, 3, p2);
		assertEquals(600,test1.getAttractiveness());
		test1.addPlant(true, 1, 0, p3);
		assertEquals(675,test1.getAttractiveness());
		test1.addPlant(false, 0, 3, p4);
		assertEquals(675,test1.getAttractiveness());
		test1.addPlant(true, 1, 2, p3);
		assertEquals(735,test1.getAttractiveness());
	}

	@Test
	public void testSendCustomer() {
		//TODO finish testing
		CollisionDetector.setStore(test1);
		test1.increaseAttractiveness(100);
		test1.updateTotalScore(100);
		test1.sendCustomer();
		assertEquals(1, test1.getCustomers().size());
		test1.sendCustomer();
		assertEquals(1, test1.getCustomers().size());
		
		test1.updateTotalScore(1500);
		//Now there should only be a 1 in 3 chance of getting a customer
		test1.sendCustomer();
		test1.sendCustomer();
		test1.sendCustomer();
		assertTrue(test1.getCustomers().size() <= 3);
	}

	@Test
	public void testSendCustomerCustomer() {
		//TODO finish testing
		CollisionDetector.setStore(test1);
		test1.sendCustomer(Customer.makeCustomer());
		assertEquals(1, test1.getCustomers().size());
		test1.sendCustomer(Customer.makeCustomer());
	}

	@Test
	public void testFindGoalLoc() {
		Customer c = Customer.makeCustomer(2,new Characteristics(new int[]{5,5,10,5,5}));
		test1.addCustomer(c);
		
		Plant p = new WhiteOak();
		test1.addPlant(true, 1, 3, p);
		c.setGoalPlant(test1.findGoalPlant(c));
		Location l = test1.findGoalLoc(c);
		assertEquals(new Location(875, 340), l);
	}

	@Test
	public void testFindGoalPlant() {
		Customer c = Customer.makeCustomer(2, new Characteristics(new int[]{5,6,10,8,9}));
		test1.addCustomer(c);
		
		Plant p2 = new WhiteOak();
		test1.addPlant(true, 1, 3, p2);
		
		Plant p = test1.findGoalPlant(c);
		assertEquals(p2.getClass(),p.getClass());
	}

	@Test
	public void testGetPlantAtLocIntInt() {
		Plant p1 = new JapaneseBarberry();
		Plant p2 = new WhiteOak();
		Plant p3 = new SweetPepperbush();
		Plant p4 = new BurningBush();
		test1.addPlant(true, 0, 1, p1);
		test1.addPlant(true, 1, 3, p2);
		test1.addPlant(true, 1, 0, p3);
		
		p1.setLoc(400, 400);
		p2.setLoc(500, 500);
		p3.setLoc(600, 600);
		
		assertEquals(new Location(0, 1), test1.getPlantAtLoc(400, 400));
		assertEquals(new Location(1, 3), test1.getPlantAtLoc(500, 500));
		assertEquals(new Location(1, 0), test1.getPlantAtLoc(600, 600));
		assertEquals(null, test1.getPlantAtLoc(100, 100));
	}

	@Test
	public void testGetPlantAtLocBooleanIntInt() {
		Plant p1 = new JapaneseBarberry();
		Plant p2 = new WhiteOak();
		Plant p3 = new SweetPepperbush();
		Plant p4 = new BurningBush();
		test1.addPlant(true, 0, 1, p1);
		test1.addPlant(true, 1, 3, p2);
		test1.addPlant(true, 1, 0, p3);
		test1.addPlant(false, 0, 3, p4);
		
		p1.setLoc(400, 400);
		p2.setLoc(500, 500);
		p3.setLoc(600, 600);
		p4.setLoc(200, 200);
		
		assertEquals(new Location(0, 1), test1.getPlantAtLoc(true, 400, 400));
		assertEquals(new Location(1, 3), test1.getPlantAtLoc(true, 500, 500));
		assertEquals(new Location(1, 0), test1.getPlantAtLoc(true, 600, 600));
		assertEquals(new Location(0, 3), test1.getPlantAtLoc(false, 200, 200));
		assertEquals(null, test1.getPlantAtLoc(false, 100, 100));
	}

	@Test
	public void testIncreaseAttractiveness() {
		assertEquals(500, test1.getSellRating());
		test1.increaseAttractiveness(400);
		assertEquals(900, test1.getSellRating());
	}

	@Test
	public void testUpdateSellRating() {
		assertEquals(500, test1.getSellRating());
		test1.updateSellRating(400);
		assertEquals(400, test1.getSellRating());
	}

}
